import { BaseInfo } from '../../serve/interfaces'
import * as apis from '../../serve/actions/upload'
import { __PUBLIC_PATH__ } from '../common'
import { Fetch, C, fetchHeaders } from './Fetch'
import { hashFile } from '@/utils/md5'
const api_base = __PUBLIC_PATH__

const begin_upload: C<typeof apis.begin_upload> = (info) => Fetch(`${api_base}/begin_upload`, info)

export const download = (_id: BaseInfo['_id'], filename: string) => `${api_base}/download/${filename}?id=${_id}`

export const do_upload = async (file: File, {
  onanalyse,
  onprogress,
  onsuccess,
  onerror,
}: {
  onanalyse?: (loaded: number, total: number) => void;
  onprogress?: (loaded: number, total: number, xhr: XMLHttpRequest) => void;
  onsuccess?: (id: BaseInfo['_id'], md5: string) => void;
  onerror?: (err: string) => void;
} = {}) => {
  let md5: string
  try {
    md5 = await hashFile(file, { chunkSize: 1024 * 1024, onanalyse })
  } catch (e) {
    onerror?.(e)
    return
  }
  const res = await begin_upload({ filename: file.name, size: file.size, md5 })
  if (res?.error) {
    onerror?.(res.error)
    return
  }
  const info = res.data
  if (info?.loaded >= file.size) {
    onsuccess?.(info._id, md5)
    return
  }
  const xhr = new XMLHttpRequest()
  xhr.addEventListener('readystatechange', function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        const res = JSON.parse(xhr.responseText)
        if (res.error) {
            onerror?.(res.error)
        } else {
            onsuccess?.(info?._id, md5)
        }
      } else {
        onerror?.('上传异常')
      }
    }
  })
  xhr.addEventListener('error', () => onerror?.('上传异常'))
  xhr.addEventListener('abort', () => onerror?.('终止上传'))
  xhr.upload.addEventListener('progress', function (e) {
    onprogress?.(e.loaded + info?.loaded, file.size, xhr)
  })
  xhr.open('POST', `${api_base}/do_upload?md5=${md5}`, true)
  const headers = fetchHeaders('post')
  Object.entries(headers).forEach(([k, v]) => {
    xhr.setRequestHeader(k, v)
  })
  xhr.send(file.slice(info?.loaded))
}
